#pragma once
#include <list>
#include <array>
#include <string>
#include <utility>
#include <concepts>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <type_traits>

#include <cmath>
#include <cstring>

#include "runtime check.hpp"

#define MAX_NUM_PER_NODE 999999999999999999
#define MAX_DIGIT_PER_NODE 18

class hyper_number
{
private:
    enum class number_symbol : size_t
    {
        positive = 0,
        negative = 1
    };
    using number_symbol::positive;
    using number_symbol::negative;
public:
    hyper_number(number_symbol symbol = positive)
        : _digits(0)
        , _symbol(symbol)
    {
        _number.push_front(0);
        ++_digits;
    }

    hyper_number(std::integral auto input)
        : _digits(0)
        , _symbol(positive)
    {
        if (input < 0)
        {
            _symbol = negative;
            input = -input;
        }
        if (input > MAX_NUM_PER_NODE)
        {
            _number.push_front(input % static_cast<unsigned long long>(pow(10, MAX_DIGIT_PER_NODE)));
            _number.push_front(input / static_cast<unsigned long long>(pow(10, MAX_DIGIT_PER_NODE)));
        }
        else
        {
            _number.push_front(input);
        }
        _digits += how_many_digit(input);
    }

    hyper_number(const char* input)
        : _digits(0)
        , _symbol(positive)
    {
        size_t len = strlen(input), cur_digit = 0;
        unsigned long long tem = 0;
        for (const char* rit = input + len - 1; rit != input - 1;)
        {
            if (rit == input)
            {
                if (*rit == '-')
                {
                    _symbol = negative;
                    continue;
                }
            }
            runtime_check()((*rit >= '0' || *rit <= '9'), "invalid char");
            if (cur_digit < MAX_DIGIT_PER_NODE)
            {
                tem += static_cast<unsigned long long>(pow(10, cur_digit)) * 
                      (static_cast<unsigned long long>(*rit) - '0');
                ++cur_digit;
                --rit;
            }
            else
            {
                _digits += cur_digit;
                cur_digit = 0;
                _number.push_front(tem);
                tem = 0;
            }
        }
        if (tem != 0)
        {
            _digits += cur_digit;
            cur_digit = 0;
            _number.push_front(tem);
            tem = 0;
        }
    }

    hyper_number(const std::string& input)
        : _digits(0)
        , _symbol(positive)
    {
        size_t cur_digit = 0;
        unsigned long long tem = 0;
        for (auto rit = input.rbegin(); rit != input.rend(); ++rit)
        {
            if (rit == input.rend() - 1)
            {
                if (*rit == '-')
                {
                    _symbol = negative;
                    continue;
                }
            }
            runtime_check()((*rit >= '0' || *rit <= '9'), "invalid char");
            if (cur_digit < MAX_DIGIT_PER_NODE)
            {
                tem += static_cast<unsigned long long>(pow(10, cur_digit)) * 
                      (static_cast<unsigned long long>(*rit) - '0');
                ++cur_digit;
            }
            else
            {
                _digits += cur_digit;
                cur_digit = 0;
                _number.push_front(tem);
                tem = 0;
            }
        }
        if (tem != 0)
        {
            _digits += cur_digit;
            cur_digit = 0;
            _number.push_front(tem);
            tem = 0;
        }
    }

    hyper_number(const hyper_number& other)
        : _number(other._number)
        , _digits(other._digits)
        , _symbol(other._symbol)
    {}

    hyper_number(hyper_number&& other) noexcept
        : _number(std::move(other._number))
        , _digits(other._digits)
        , _symbol(other._symbol)
    {}

    const hyper_number& operator=(const hyper_number& other)
    {
        _number = other._number;
        _digits = other._digits;
        _symbol = other._symbol;
        return *this;
    }

    const hyper_number& operator=(hyper_number&& other) noexcept
    {
        _number = std::move(other._number);
        _digits = other._digits;
        _symbol = other._symbol;
        return *this;
    }

    hyper_number operator+(const hyper_number& other) const
    {
        hyper_number ret;
        if (symbol() == other.symbol())
        {
            return greater(*this, other) ? add(*this, other, ret, static_cast<bool>(_symbol)) :
                add(other, *this, ret, static_cast<bool>(_symbol));
        }
        else
        {
            if (greater(*this, other))
            {
                return sub(*this, other, ret, static_cast<bool>(_symbol));
            }
            else
            {
                return sub(other, *this, ret, !static_cast<bool>(_symbol));
            }
        }
    }

    hyper_number& operator+=(const hyper_number& other)
    {
        if (symbol() == other.symbol())
        {
            return greater(*this, other) ? add(*this, other, *this, static_cast<bool>(_symbol)) :
                add(other, *this, *this, static_cast<bool>(_symbol));
        }
        else
        {
            if (greater(*this, other))
            {
                return sub(*this, other, *this, static_cast<bool>(_symbol));
            }
            else
            {
                return sub(other, *this, *this, !static_cast<bool>(_symbol));
            }
        }
    }

    hyper_number operator-(const hyper_number& other) const
    {
        hyper_number ret;
        if (symbol() != other.symbol())
        {
            return greater(*this, other) ? add(*this, other, ret, static_cast<bool>(_symbol)) :
                add(other, *this, ret, static_cast<bool>(_symbol));
        }
        else
        {
            if (greater(*this, other))
            {
                return sub(*this, other, ret, static_cast<bool>(_symbol));
            }
            else
            {
                return sub(other, *this, ret, !static_cast<bool>(_symbol));
            }
        }
    }

    hyper_number& operator-=(const hyper_number& other)
    {
        if (symbol() != other.symbol())
        {
            return greater(*this, other) ? add(*this, other, *this, static_cast<bool>(_symbol)) :
                add(other, *this, *this, static_cast<bool>(_symbol));
        }
        else
        {
            if (greater(*this, other))
            {
                return sub(*this, other, *this, static_cast<bool>(_symbol));
            }
            else
            {
                return sub(other, *this, *this, !static_cast<bool>(_symbol));
            }
        }
    }

    hyper_number operator*(const hyper_number& other) const
    {
        hyper_number ret;
        bool sym = (symbol() != other.symbol()) ? true : false;
        return greater(*this, other) ? mul(*this, other, ret, sym) : mul(other, *this, ret, sym);
    }

    hyper_number& operator*=(const hyper_number& other)
    {
        bool sym = (symbol() != other.symbol()) ? true : false;
        return greater(*this, other) ? mul(*this, other, *this, sym) : mul(other, *this, *this, sym);
    }

    hyper_number operator/(const hyper_number& other) const
    {
        runtime_check()(other != 0, "divied by zero");
        hyper_number ret;
        return greater(*this, other) ? quotient(other, ret) : ret;
    }

    hyper_number& operator/=(const hyper_number& other)
    {
        runtime_check()(other != 0, "divied by zero");
        return greater(*this, other) ? quotient(other, *this) : (*this = 0, *this);
    }

    hyper_number operator%(const hyper_number& other) const
    {
        runtime_check()(other != 0, "divied by zero");
        hyper_number ret;
        return greater(*this, other) ? remainder(other, ret) : *this;
    }

    hyper_number& operator%=(const hyper_number& other)
    {
        runtime_check()(other != 0, "divied by zero");
        return greater(*this, other) ? remainder(other, *this) : *this;
    }

    number_symbol& symbol()
    {
        if (_digits == 1 && _number.back() == 0 && _symbol == negative)
        {
            _symbol = positive;
        }
        return _symbol;
    }

    number_symbol symbol() const
    {
        if (_digits == 1 && _number.back() == 0 && _symbol == negative)
        {
            return positive;
        }
        return _symbol;
    }

    std::pair<hyper_number, hyper_number> quotient_and_remainder(const hyper_number& num) const
    {
        runtime_check()((num != 0), "divied by zero");
        bool is_minus_quo, is_minus_rem;
        hyper_number quo, rem;
        if (less(*this, num))
        {
            quo = 0;
            rem = *this;
            return std::make_pair(quo, rem);
        }
        if (static_cast<bool>(symbol()))
        {
            is_minus_rem = true;
            is_minus_quo = static_cast<bool>(num.symbol()) ? false : true;
        }
        else
        {
            is_minus_rem = false;
            is_minus_quo = static_cast<bool>(num.symbol()) ? true : false;
        }
        div_and_rem(*this, num, &quo, &rem, is_minus_quo, is_minus_rem);
        return std::make_pair(quo, rem);
    }

    void print()
    {
        std::cout << "digit: " << _digits << std::endl;
        if (_symbol == number_symbol::negative)
        {
            std::cout << '-';
        }
        for (auto it = _number.begin(); it != _number.end(); ++it)
        {
            if (*it <= MAX_NUM_PER_NODE / 10 && it != _number.begin())
            {
                size_t align_digit = MAX_DIGIT_PER_NODE - how_many_digit(*it);
                for (size_t i = 0; i < align_digit; ++i)
                {
                    std::cout << '0';
                }
            }
            std::cout << *it;
        }
        std::cout << std::endl;
    }

    bool operator==(const hyper_number& other) const
    {
        return symbol() != other.symbol() ? false : equal(*this, other);
    }

    bool operator!=(const hyper_number& other) const
    {
        return !(*this == other);
    }

    bool operator>(const hyper_number& other) const
    {
        if (symbol() != other.symbol())
        {
            return static_cast<bool>(symbol()) ? false : true;
        }
        else
        {
            return static_cast<bool>(symbol()) ? less(*this, other) : greater(*this, other);
        }
    }

    bool operator<(const hyper_number& other) const
    {
        if (symbol() != other.symbol())
        {
            return static_cast<bool>(symbol()) ? true : false;
        }
        else
        {
            return static_cast<bool>(symbol()) ? greater(*this, other) : less(*this, other);
        }
    }

    bool operator>=(const hyper_number& other) const
    {
        return *this > other || *this == other;
    }

    bool operator<=(const hyper_number& other) const
    {
        return *this < other || *this == other;
    }
private:
    static hyper_number& add(const hyper_number& num1, const hyper_number& num2, hyper_number& ret, bool symbol)
    {
        auto rit_r = ret._number.rbegin();
        if (ret._number.size() < num1._number.size())
        {
            ret._number.insert(ret._number.begin(), num1._number.size() - ret._number.size(), 0);
        }
        ret._symbol = _conv[symbol];
        auto rit1 = num1._number.rbegin(), rit2 = num2._number.rbegin();
        unsigned long long overflow = 0, tem = 0;
        while (rit2 != num2._number.rend())
        {
            tem = *rit1 + *rit2 + overflow;
            if (tem > MAX_NUM_PER_NODE)
            {
                *rit_r = tem % static_cast<unsigned long long>(pow(10, MAX_DIGIT_PER_NODE));
                overflow = tem / static_cast<unsigned long long>(pow(10, MAX_DIGIT_PER_NODE));
            }
            else
            {
                *rit_r = tem;
                overflow = 0;
            }
            ++rit1, ++rit2, ++rit_r;
        }
        while (rit1 != num1._number.rend())
        {
            tem = *rit1 + overflow;
            if (tem > MAX_NUM_PER_NODE)
            {
                *rit_r = tem % static_cast<unsigned long long>(pow(10, MAX_DIGIT_PER_NODE));
                overflow = tem / static_cast<unsigned long long>(pow(10, MAX_DIGIT_PER_NODE));
            }
            else
            {
                *rit_r = tem;
                overflow = 0;
            }
            ++rit1, ++rit_r;
        }
        if (overflow != 0)
        {
            ret._digits = num1._digits;
            ret._number.push_front(overflow);
            ret._digits += how_many_digit(overflow);
        }
        else
        {
            if (num1._digits % MAX_DIGIT_PER_NODE == 0)
            {
                ret._digits = num1._digits - MAX_DIGIT_PER_NODE;
            }
            else
            {
                ret._digits = num1._digits - num1._digits % MAX_DIGIT_PER_NODE;
            }
            ret._digits += how_many_digit(ret._number.front());
        }
        return ret;
    }

    static hyper_number& sub(const hyper_number& num1, const hyper_number& num2, hyper_number& ret, bool symbol)
    {
        if (equal(num1, num2))
        {
            ret._number.resize(1);
            ret._number.front() = 0;
            ret._digits = 1;
            ret._symbol = number_symbol::positive;
            return ret;
        }
        ret._symbol = _conv[symbol];
        auto rit_r = ret._number.rbegin();
        if (ret._number.size() < num1._number.size())
        {
            ret._number.insert(ret._number.begin(), num1._number.size() - ret._number.size(), 0);
        }
        auto rit1 = num1._number.rbegin(), rit2 = num2._number.rbegin();
        bool flag = false;
        long long tem = 0;
        while (rit2 != num2._number.rend())
        {
            tem = *rit1 - *rit2;
            if (flag)
            {
                tem -= 1;
            }
            if (tem < 0)
            {
                flag = true;
                tem += MAX_NUM_PER_NODE + 1;
            }
            else
            {
                flag = false;
            }
            *rit_r = tem;
            ++rit1, ++rit2, ++rit_r;
        }
        while (rit1 != num1._number.rend())
        {
            tem = *rit1;
            if (flag)
            {
                tem -= 1;
            }
            if (tem < 0)
            {
                flag = true;
                tem += MAX_NUM_PER_NODE + 1;
            }
            else
            {
                flag = false;
            }
            *rit_r = tem;
            ++rit1, ++rit_r;
        }
        ret._digits = num1._digits;    
        ret._digits -= num1._digits % MAX_DIGIT_PER_NODE == 0 ? MAX_DIGIT_PER_NODE : num1._digits % MAX_DIGIT_PER_NODE;
        while (ret._number.front() == 0)
        {
            ret._number.pop_front();
            ret._digits -= MAX_DIGIT_PER_NODE;
        }
        ret._digits += how_many_digit(ret._number.front());
        return ret;
    }

    static hyper_number& mul(const hyper_number& num1, const hyper_number& num2, hyper_number& ret, bool symbol)
    {
        auto rit1 = num1._number.rbegin(), rit2 = num2._number.rbegin();
        std::array<hyper_number, 10> mul_value;
        hyper_number first_prod_val, final_prod_val;
        unsigned long long tem = 0;
        size_t cur_digit = num2._digits;
        for (size_t i = 0; i < 10; ++i)
        {
            if (i != 0)
            {
                if (greater(mul_value[i - 1], num1))
                {
                    add(mul_value[i - 1], num1, mul_value[i], false);
                }
                else
                {
                    add(num1, mul_value[i - 1], mul_value[i], false);
                }
            }
        }

        for (size_t i = 0; rit2 != num2._number.rend(); ++i)
        {
            tem = *rit2;
            for (size_t j = 0; j < MAX_DIGIT_PER_NODE && j < cur_digit; ++j)
            {
                append_digit(mul_value[tem % 10], first_prod_val, i * MAX_DIGIT_PER_NODE + j);
                tem /= 10;
                if (greater(final_prod_val, first_prod_val))
                {
                    add(final_prod_val, first_prod_val, final_prod_val, symbol);
                }
                else
                {
                    add(first_prod_val, final_prod_val, final_prod_val, symbol);
                }
            }
            cur_digit -= MAX_DIGIT_PER_NODE;
            ++rit2;
        }
        ret = final_prod_val;
        ret._symbol = _conv[symbol];
        return ret;
    }

    static void div_and_rem(const hyper_number& num1, const hyper_number& num2,
        hyper_number* quo_ptr, hyper_number* rem_ptr, bool symbol_quo, bool symbol_rem)
    {
        auto rit1 = num1._number.rbegin(), rit2 = num2._number.rbegin();
        hyper_number tem = num1;
        hyper_number q;
        std::array<hyper_number, 10> mul_value;
        for (size_t i = 1; i < 10; ++i)
        {
            if (greater(mul_value[i - 1], num2))
            {
                add(mul_value[i - 1], num2, mul_value[i], false);
            }
            else
            {
                add(num2, mul_value[i - 1], mul_value[i], false);
            } 
        }
        for (size_t i = 1; i < 10; ++i)
        {
            append_digit(mul_value[i], mul_value[i], num1._digits - num2._digits);
        }
        for (size_t i = num1._digits - num2._digits + 1; i > 0; --i)
        {
            for (size_t j = 1; j <= 10; ++j)
            {
                if (j == 10 || greater(mul_value[j], tem))
                {
                    sub(tem, mul_value[j - 1], tem, symbol_quo);
                    if (quo_ptr != nullptr)
                    {
                        put(q, j - 1, i);
                    }
                    break;
                }
            }
            for (size_t j = 1; j <= 10; ++j)
            {
                remove_digit(mul_value[j - 1], mul_value[j - 1], 1);
            }
        }
        if (rem_ptr != nullptr)
        {
            *rem_ptr = std::move(tem);
            rem_ptr->_symbol = _conv[symbol_rem];
        }
        if (quo_ptr != nullptr)
        {
            *quo_ptr = q;
        }
    }

    hyper_number& quotient(const hyper_number& num, hyper_number& quo) const
    {
        bool sym = (symbol() != num.symbol()) ? true : false;
        div_and_rem(*this, num, &quo, nullptr, sym, sym);
        return quo;
    }

    hyper_number& remainder(const hyper_number& num, hyper_number& rem) const
    {
        bool sym = static_cast<bool>(symbol());
        div_and_rem(*this, num, &rem, nullptr, sym, sym);
        return rem;
    }

    static size_t how_many_digit(unsigned long long input)
    {
        size_t ret = 0;
        if (input == 0)
        {
            ret = 1;
        }
        while (input > 0)
        {
            input /= 10;
            ++ret;
        }
        return ret;
    }

    static hyper_number& put(hyper_number& num, size_t input, size_t which_digit)
    {
        runtime_check()((input >= 0 && input <= 9), "out of range");
        if (input == 0)
        {
            return put_zero(num, which_digit);
        }
        size_t new_size = which_digit / MAX_DIGIT_PER_NODE + (which_digit % MAX_DIGIT_PER_NODE ? 1 : 0);
        size_t effective_digit = which_digit % MAX_DIGIT_PER_NODE ? which_digit % MAX_DIGIT_PER_NODE : MAX_DIGIT_PER_NODE;
        unsigned long long divided_num = static_cast<unsigned long long>(pow(10, effective_digit - 1));
        if (num._digits < which_digit)
        {
            num._digits = which_digit;
            if (num._number.size() < new_size)
            {
                num._number.insert(num._number.begin(), new_size - num._number.size(), 0);
            }
            num._number.front() += input * divided_num;
        }
        else
        {
            {
                size_t cur_digit = 0, tem = 0;
                for (auto rit = num._number.rbegin(); rit != num._number.rend(); ++rit)
                {
                    cur_digit += MAX_DIGIT_PER_NODE;
                    if (cur_digit >= which_digit)
                    {
                        tem = *rit % divided_num;
                        *rit /= divided_num * 10;
                        *rit *= 10;
                        *rit += input;
                        *rit = *rit * divided_num + tem;
                        break;
                    }
                }
            }
        }
        return num;
    }

    static hyper_number& put_zero(hyper_number& num, size_t which_digit)
    {
        if (num._digits < which_digit)
        {
            return num;
        }
        size_t cur_digit = 0, tem = 0;
        size_t effective_digit = which_digit % MAX_DIGIT_PER_NODE ? which_digit % MAX_DIGIT_PER_NODE : MAX_DIGIT_PER_NODE;
        unsigned long long divided_num = static_cast<unsigned long long>(pow(10, effective_digit - 1));
        for (auto rit = num._number.rbegin(); rit != num._number.rend(); ++rit)
        {
            cur_digit += MAX_DIGIT_PER_NODE;
            if (cur_digit >= which_digit)
            {
                tem = *rit % divided_num;
                *rit /= divided_num * 10;
                *rit = *rit * divided_num * 10 + tem;
                break;
            }
        }
        if (num._digits == which_digit)
        {
            auto it = num._number.begin();
            while (it != num._number.end())
            {
                if (how_many_digit(*it) == 0)
                {
                    ++it;
                }
                else
                {
                    num._number.erase(num._number.begin(), it);
                    num._digits = (num._number.size() - 1) * MAX_DIGIT_PER_NODE + how_many_digit(*it);
                }
            }
        }
        return num;
    }

    static hyper_number& append_digit(const hyper_number& num, hyper_number& ret, size_t digits)
    {
        if (digits == 0 || equal(num, 0))
        {
            ret = num;
            return ret;
        }
        if (num._number.front() == 0 && num._digits == 1)
        {
            ret = 0;
            return ret;
        }
        if (ret._number.size() < num._number.size())
        {
            ret._number.resize(num._number.size(), 0);
        }
        auto rit_s = num._number.rbegin();
        auto rit_d = ret._number.rbegin();
        if (ret._number.size() > num._number.size())
        {
            size_t tem = ret._number.size() - num._number.size();
            for (size_t i = 0; i < tem; ++i, ++rit_d)
            {
                *rit_d = 0;
            }
        }
        ++rit_s, ++rit_d;
        ret._number.resize(num._number.size() + digits / MAX_DIGIT_PER_NODE, 0);
        --rit_s, --rit_d;
        size_t effective_digit = digits % MAX_DIGIT_PER_NODE;
        if (effective_digit == 0)
        {
            for (; rit_s != num._number.rend(); ++rit_s, ++rit_d)
            {
                *rit_d = *rit_s;
            }
            ret._digits = digits + num._digits;
            return ret;
        }
        unsigned long long cur_overflow = 0, prev_overflow = 0, tem = 0;
        size_t divied_num = static_cast<size_t>(pow(10, MAX_DIGIT_PER_NODE - effective_digit));
        while (rit_s != num._number.rend())
        {
            cur_overflow = *rit_s / divied_num;
            tem = (*rit_s % divied_num) * ((MAX_NUM_PER_NODE + 1) / divied_num) + prev_overflow;
            prev_overflow = cur_overflow;
            *rit_d = tem;
            ++rit_s, ++rit_d;
        }
        if (prev_overflow != 0)
        {
            if (rit_d != ret._number.rend())
            {
                *rit_d = prev_overflow;
            }
            else
            {
                ret._number.push_front(prev_overflow);
            }
        }
        ret._digits = digits + num._digits;
        return ret;
    }

    static hyper_number& remove_digit(const hyper_number& num, hyper_number& ret, size_t digits)
    {
        if (digits == 0)
        {
            ret = num;
            return ret;
        }
        if (digits >= num._digits)
        {
            ret._number.resize(1, 0);
            ret._digits = 1;
            ret._symbol = positive;
            return ret;
        }
        ret._digits -= digits;
        size_t effective_digit = digits % MAX_DIGIT_PER_NODE;
        auto it_s = num._number.begin();
        auto it_d = ret._number.begin();
        ret._number.resize(num._number.size() - digits / MAX_DIGIT_PER_NODE);
        if (effective_digit == 0)
        {
            for (; it_d != ret._number.end(); ++it_s, ++it_d)
            {
                *it_d = *it_s;
            }
            return ret;
        }
        unsigned long long cur_overflow = 0, prev_overflow = 0, tem = 0;
        size_t divied_num1 = static_cast<size_t>(pow(10, effective_digit));
        size_t divied_num2 = static_cast<size_t>(pow(10, MAX_DIGIT_PER_NODE - effective_digit));
        while (it_d != ret._number.end())
        {
            cur_overflow = *it_s % divied_num1;
            tem = prev_overflow * divied_num2 + *it_s / divied_num1;
            prev_overflow = cur_overflow;
            *it_d = tem;
            ++it_s, ++it_d;
        }
        if (ret._number.front() == 0)
        {
            ret._number.pop_front();
        }
        return ret;
    }

    static bool greater(const hyper_number& num1, const hyper_number& num2)
    {
        if (num1._digits > num2._digits)
        {
            return true;
        }
        else if (num1._digits < num2._digits)
        {
            return false;
        }
        else
        {
            for (auto it1 = num1._number.begin(), it2 = num2._number.begin();
                it1 != num1._number.end() && it2 != num2._number.end(); ++it1, ++it2)
            {
                if (*it1 > *it2)
                {
                    return true;
                }
                else if (*it1 < *it2)
                {
                    return false;
                }
            }
            return false;
        }
    }

    static bool less(const hyper_number& num1, const hyper_number& num2)
    {
        if (num1._digits > num2._digits)
        {
            return false;
        }
        else if (num1._digits < num2._digits)
        {
            return true;
        }
        else
        {
            for (auto it1 = num1._number.begin(), it2 = num2._number.begin();
                it1 != num1._number.end() && it2 != num2._number.end(); ++it1, ++it2)
            {
                if (*it1 > *it2)
                {
                    return false;
                }
                else if (*it1 < *it2)
                {
                    return true;
                }
            }
            return false;
        }
    }

    static bool equal(const hyper_number& num1, const hyper_number& num2)
    {
        if (num1._digits > num2._digits)
        {
            return false;
        }
        else if (num1._digits < num2._digits)
        {
            return false;
        }
        else
        {
            for (auto it1 = num1._number.begin(), it2 = num2._number.begin();
                it1 != num1._number.end() && it2 != num2._number.end(); ++it1, ++it2)
            {
                if (*it1 > *it2)
                {
                    return false;
                }
                else if (*it1 < *it2)
                {
                    return false;
                }
            }
            return true;
        }
    }
private:
    constexpr static const number_symbol _conv[2] = { positive, negative };
private:
    std::list<unsigned long long> _number;
    size_t _digits;
    number_symbol _symbol;
};